﻿// Global namespace
var MasterStroke = MasterStroke || {};

define
(
    ["require",
     "lib/knockout",
     "Common/OrderedChangeIdSet",
     "./Shape", 
     "./Types",
     "Common/Validate"],
    function (require, ko, OrderedChangeIdSet, Validate)
    {
        MasterStroke.Frame = function (changeId)
        {
            this.changeId = changeId;
            this.shapes = ko.observableArray([]);
            this.images = ko.observableArray([]);
            this.newReviewAvailable = ko.observable(false);
            var _referenceFrames = new OrderedChangeIdSet();
            this.referenceFrames = ko.observableArray(_referenceFrames.bindingSource());

            // Adds a shape or a collection of shapes to the frame
            this.addShape = function(shape, local)
            {
                var annotation = false;

                if (shape instanceof fabric.PathGroup)
                {
                    var shapes = shape.getObjects();
                    for (var i = 0; i < shapes.length; i++)
                    {
                        annotation |= shapes[i].annotation;
                        this.shapes.push(new MasterStroke.Shape(shapes[i]));
                    }
                }
                else if (shape instanceof fabric.Object)
                {
                    annotation |= shape.annotation;
                    this.shapes.push(new MasterStroke.Shape(shape));
                }
                else if (MasterStroke.Types.isArray(shape))
                {
                    for (var i = 0; i < shape.length; i++)
                    {
                        annotation |= shape[i].annotation;
                        this.shapes.push(new MasterStroke.Shape(shape[i]));
                    }
                }
                else
                {
                    throw "shape must be a fabric object";
                }

                if ((!local) && annotation)
                {
                    this.newReviewAvailable(true);
                }
            };

            this.select = function()
            {
                this.newReviewAvailable(false); 
            };

            this.getShape = function(changeId)
            {
                var shape;
                var shapes = this.shapes();

                for (var i = 0; i < shapes.length; i++)
                {                    
                    if (shapes[i].getShape().changeId === changeId)
                    {
                        shape = shapes[i];
                        break;
                    }
                }

                return shape;
            };

            this.deleteShape = function(changeId)
            {
                var shapes = this.shapes();

                for (var i = 0; i < shapes.length; i++)
                {
                    var shape = shapes[i];
                    if (shape.getShape().changeId === changeId)
                    {
                        this.shapes.remove(shape);
                        return;
                    }
                }
            };

            this.updateShapes = function(shapes)
            {
                for (var i = 0; i < shapes.length; i++)
                {
                    this.deleteShape(shapes[i].changeId);
                }                

                for (var i = 0; i < shapes.length; i++)
                {
                    this.addShape(shapes[i]);                    
                }
            }

            this.clone = function(changeId)
            {
                var frame = new MasterStroke.Frame(changeId);
                var shapes = this.shapes();
                for (var i = 0; i < shapes.length; i++)
                {
                    var shape = shapes[i].getShape().clone();
                    
                    shape.toObject = (function(toObject)
                    {
                        return function()
                        {
                            return fabric.util.object.extend(toObject.call(this), {changeId: this.changeId});                        
                        }
                    }(shape.toObject));

                    frame.addShape(shape);
                }
                return frame;
            };

            this.getShapes = function ()
            {
                // Clones the array
                // Note: This prevents modification of _shapes
                //       and also the MasterStroke.Shape is duplicated
                //       but not the inner fabric.Object
                return this.shapes.slice(0);
            };

            this.addReferenceFrame = function(referenceFrame)
            {
                _referenceFrames.add(referenceFrame.changeId, referenceFrame);
                this.referenceFrames.valueHasMutated();
            };

            this.removeReferenceFrame = function(referenceFrameChangeId)
            {
                _referenceFrames.delete(referenceFrameChangeId);
                this.referenceFrames.valueHasMutated();
            };

            this.toJSON = function()
            {                
                return {changeId: this.changeId, shapes: this.shapes()};
            }
        };

        return MasterStroke.Frame;
    }
);